package com.taysear.bus;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import com.taysear.bus.util.Constants;
import com.taysear.bus.util.Results;
import com.taysear.bus.util.Util;
import com.taysear.dbservice.DbServicesPrx;
import com.taysear.dbservice.ServiceParameter;
import com.taysear.dbservice.ServiceResult;
import com.taysear.domain.Booking;
import com.taysear.domain.BusFare;
import com.taysear.domain.Country;
import com.taysear.domain.Route;
import com.taysear.domain.Seat;
import com.taysear.domain.Substation;
import com.taysear.domain.SystemConfiguration;
import com.taysear.domain.helper.Temp;
import com.vaadin.data.Validator;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.BeanContainer;
import com.vaadin.data.util.BeanItem;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.data.validator.StringLengthValidator;
import com.vaadin.terminal.ExternalResource;
import com.vaadin.ui.Button;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.CustomLayout;
import com.vaadin.ui.DateField;
import com.vaadin.ui.Form;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Layout;
import com.vaadin.ui.NativeSelect;
import com.vaadin.ui.OptionGroup;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.themes.Runo;

/**
 * <code>CreateBooking</code> is used to create and change a booking.
 * 
 * @author Abdullahi
 *
 */
@SuppressWarnings("serial")
public class CreateBooking extends HorizontalLayout{

	String bookingId = null;
	Boolean isOneWay = true;
	String actionDate = null;
	Map<String, String> bookingResult = null;
	Booking booking = null;
	BusFare busFare = null;
	
	Form form = new Form();
	OptionGroup bookingType;
	ComboBox seat = null;
	ComboBox departureSeat = null;
	ComboBox returnSeat = null;
	ComboBox amount = null;
	ComboBox fromSubstation = null;
	ComboBox toSubstation = null;
	ComboBox route = null;
	DateField travelDate = null;
	DateField departureDate = null;
	DateField returnDate = null;
	TextField customerName = null;
	TextField customerMobile = null;
	ComboBox nationality = null;
	TextField idNumber = null;
	TextField pickupPoint = null;
	TextField childAge = null;
	NativeSelect nrOfAdults = null;
	NativeSelect nrOfChildren = null;
	
	OptionGroup departureRoutes = null;
	OptionGroup returnRoutes = null;
	
	VerticalLayout createBookingStep1 = null;
	VerticalLayout createBookingStep2 = null;
	VerticalLayout createBookingStep3 = null;
	VerticalLayout createBookingStep4 = null;
	
	Results availableDepartureSeats = null;
	Results availableReturnSeats = null;
	Map<Integer, PassengerDetailForm> passengers = null;
	
	/**
	 * Constructor used for new booking.
	 */
	public CreateBooking() {
		//Form createBookingForm = getCreateBookingForm();
		
		//addComponent(createBookingForm);
		addComponent(createBookingStep1());
	}
	
	/**
	 * Constructor used for editing booking.
	 * 
	 * @param booking
	 * @param caption
	 */
	public CreateBooking(String caption, Booking booking) {
		this.booking = booking; 
		Form editBookingForm = getChangeBookingForm(caption);
		
		addComponent(editBookingForm);
	}
	
	/**
	 * Gets a form that is used to create a booking.
	 * 
	 * @return Form
	 */
	private Form getCreateBookingForm() {
		form.setCaption("Create booking");
		
		bookingType = getBookingTypeOptions();
		seat = getSeatDropdown("Seat");
		amount = getAmountDropdown();
		fromSubstation = getFromSubstationDropdown();
		toSubstation = getToSubstationDropdown();
		route = getRouteDropdown();
		route.focus();
		travelDate = getTravelDateField();
		customerName = getCustomerNameTextfield();
		customerMobile = getCustomerMobileTextfield();
		nationality = getNationalityDropdown();
		idNumber = getIdNumberTextfield();
		pickupPoint = getPickupPointTextfield();
		childAge = getChildAgeTextField();
		
		fromSubstation.addListener(getValueChangeListenerForSubstation());
		toSubstation.addListener(getValueChangeListenerForSubstation());
		
		form.addField("bookingType", bookingType);
		form.addField("travelDate", travelDate);
		form.addField("route", route);
		form.addField("fromSubstation", fromSubstation);
		form.addField("toSubstation", toSubstation);
		form.addField("amount", amount);
		form.addField("seat", seat);
		form.addField("name", customerName);
		form.addField("mobile", customerMobile);
		form.addField("nationality", nationality);
		form.addField("idNumber", idNumber);
		form.addField("pickupPoint", pickupPoint);
		form.addField("childAge", childAge);
		
		HorizontalLayout footer = (HorizontalLayout) form.getFooter();
		footer.addStyleName("formFooter");
		footer.setSpacing(true);

		Button print = getPrintButton(form);
		Button save = getSaveButton(form, print);
		
		footer.addComponent(save);
		footer.addComponent(print);
		
		return form;
	}

	/**
	 * Creates a layout that is used for the first step in the create booking form.
	 * 
	 * @return Layout
	 */
	private Layout createBookingStep1() {
		bookingType = getBookingTypeOptions();
		fromSubstation = getFromSubstationDropdown();
		fromSubstation.focus();
		toSubstation = getToSubstationDropdown();
		departureDate = getDepartureDateField();
		returnDate = getReturnDateField();
		nrOfAdults = getNrOfAdulsDropdown();
		nrOfChildren = getNrOfChildrenDropdown();
		
		loadSubstationsDropdown();
		
		createBookingStep1 = new VerticalLayout();
		createBookingStep1.setSpacing(true);
		
		Panel header = new Panel("Search and book bus");
		header.addStyleName(Runo.PANEL_LIGHT);
		createBookingStep1.addComponent(header);
		
		createBookingStep1.addComponent(bookingType);
		
		HorizontalLayout fromDepLayout = new HorizontalLayout();
		fromDepLayout.setSpacing(true);

		fromDepLayout.addComponent(fromSubstation);
		fromDepLayout.addComponent(departureDate);
		
		HorizontalLayout toRetLayout = new HorizontalLayout();
		toRetLayout.setSpacing(true);

		toRetLayout.addComponent(toSubstation);
		toRetLayout.addComponent(returnDate);
		
		HorizontalLayout nrOfAdCh = new HorizontalLayout();
		nrOfAdCh.setSpacing(true);
		
		nrOfAdCh.addComponent(nrOfAdults);
		nrOfAdCh.addComponent(nrOfChildren);
		
		createBookingStep1.addComponent(fromDepLayout);
		createBookingStep1.addComponent(toRetLayout);
		createBookingStep1.addComponent(nrOfAdCh);
		
		HorizontalLayout buttons = new HorizontalLayout();
		buttons.setSpacing(true);
		
		Button findBookingBtn = getFindBookingButton();
		buttons.addComponent(findBookingBtn);
		
		createBookingStep1.addComponent(buttons);
		
		return createBookingStep1;
	}
	
	/**
	 * Gets a form that is used to change a booking.
	 * 
	 * @param caption
	 * 
	 * @return Form
	 */
	private Form getChangeBookingForm(String caption) {
		form.setCaption(caption);
		
		bookingType = getBookingTypeOptions();
		seat = getSeatDropdown("Seat");
		amount = getAmountDropdown();
		fromSubstation = getFromSubstationDropdown();
		toSubstation = getToSubstationDropdown();
		route = getRouteDropdown();
		route.focus();
		travelDate = getTravelDateField();
		customerName = getCustomerNameTextfield();
		customerMobile = getCustomerMobileTextfield();
		nationality = getNationalityDropdown();
		idNumber = getIdNumberTextfield();
		pickupPoint = getPickupPointTextfield();
		childAge = getChildAgeTextField();
		
		fromSubstation.addListener(getValueChangeListenerForSubstation());
		toSubstation.addListener(getValueChangeListenerForSubstation());
		
		form.addField("bookingType", bookingType);
		form.addField("travelDate", travelDate);
		form.addField("route", route);
		form.addField("fromSubstation", fromSubstation);
		form.addField("toSubstation", toSubstation);
		form.addField("amount", amount);
		form.addField("seat", seat);
		form.addField("name", customerName);
		form.addField("mobile", customerMobile);
		form.addField("nationality", nationality);
		form.addField("idNumber", idNumber);
		form.addField("pickupPoint", pickupPoint);
		form.addField("childAge", childAge);
		
		return form;
	}
	
	public OptionGroup getBookingTypeOptions() {
		final OptionGroup optionGroup = new OptionGroup();
		optionGroup.setImmediate(true);
		optionGroup.addStyleName("horizontal"); // Lay the items out horizontally
		
		BeanContainer<Integer, Temp> container = new BeanContainer<Integer, Temp>(Temp.class);
		container.addItem(1, new Temp(Constants.BOOKING_TYPE_RETURN, "Return"));
		container.addItem(2, new Temp(Constants.BOOKING_TYPE_ONE_WAY, "One way"));
		
		optionGroup.setContainerDataSource(container);
		optionGroup.setValue(container.getItemIds().iterator().next());
		optionGroup.addListener(new ValueChangeListener() {
			@Override
			public void valueChange(ValueChangeEvent event) {
				BusApplication app = AppData.getApp();
				if(event.getProperty().getValue() != null) {
					Temp type = ((BeanItem<Temp>) optionGroup.getContainerDataSource().getItem(optionGroup.getValue())).getBean();
					if(returnDate != null) {
						if(type.getId() == Constants.BOOKING_TYPE_ONE_WAY) {
							returnDate.setValue(null);
							returnDate.setEnabled(false);
						} else {
							returnDate.setEnabled(true);
						}
					}
				}
			}
		});
		optionGroup.setItemCaptionPropertyId("description");
		
		return optionGroup;
	}
	
	/**
	 * Gets a dropdown used for displaying seat.
	 * 
	 * @return ComboBox
	 */
	public ComboBox getSeatDropdown(String caption) {
		ComboBox seat = new ComboBox(caption);
		seat.setRequired(true);
		seat.setRequiredError("This field is required");
		seat.setWidth(Constants.COMMON_FIELD_WIDTH_S);
		seat.setNullSelectionAllowed(false);
		seat.setImmediate(true);
		return seat;
	}
	
	/**
	 * Gets a dropdown used for displaying amount.
	 * 
	 * @return ComboBox
	 */
	public ComboBox getAmountDropdown() {
		ComboBox amount = new ComboBox("Amount");
		amount.setRequired(true);
		amount.setRequiredError("This field is required");
		amount.setWidth(Constants.COMMON_FIELD_WIDTH_M);
		amount.setImmediate(true);
		amount.setReadOnly(true);
		return amount;
	}
	
	/**
	 * Gets a dropdown used for displaying from substation.
	 * 
	 * @return ComboBox
	 */
	public ComboBox getFromSubstationDropdown() {
		ComboBox fromSubstation = new ComboBox("From substation");
		fromSubstation.setRequired(true);
		fromSubstation.setRequiredError("This field is required");
		fromSubstation.setWidth(Constants.COMMON_FIELD_WIDTH_M);
		fromSubstation.setNullSelectionAllowed(false);
		fromSubstation.setImmediate(true);
		return fromSubstation;
	}
	
	/**
	 * Gets a dropdown used for displaying to substations.
	 * 
	 * @return ComboBox
	 */
	public ComboBox getToSubstationDropdown() {
		ComboBox toSubstation = new ComboBox("To substation");
		toSubstation.setRequired(true);
		toSubstation.setRequiredError("This field is required");
		toSubstation.setWidth(Constants.COMMON_FIELD_WIDTH_M);
		toSubstation.setNullSelectionAllowed(false);
		toSubstation.setImmediate(true);
		return toSubstation;
	}
	
	private void loadSubstationsDropdown() {
		BusApplication app = AppData.getApp();
		
		BeanContainer<Integer, Substation> container = new BeanContainer<Integer, Substation>(Substation.class);
		container.setBeanIdProperty("substationId");
		
		ServiceParameter sp = new ServiceParameter(new HashMap<String, String>());
		
		DbServicesPrx dbServicesPrx = app.getDbServiceProxy();
		ServiceResult sr = dbServicesPrx.getAllSubstations(sp);
		if(sr.status) {
			if(sr.param.get("RECORDS") != null) {
				Results r = Util.getObjectsFromXmlResult(sr.param.get("RECORDS"), Substation.class);
				
				for (Object object : r.getRows()) {
					Substation substation = (Substation) object;
					container.addItem(substation.getSubstationId(), substation);
				}
				fromSubstation.setContainerDataSource(container);
				toSubstation.setContainerDataSource(container);
			} else {
				app.showErrorNotification("No substations where found");
				fromSubstation.setContainerDataSource(null);
				toSubstation.setContainerDataSource(null);
			}
		} else {
			app.showErrorNotification(sr.message);
			fromSubstation.setContainerDataSource(null);
			toSubstation.setContainerDataSource(null);
		}
		fromSubstation.setItemCaptionPropertyId("name");
		toSubstation.setItemCaptionPropertyId("name");
	}
	
	/**
	 * Gets a textfield used for displaying customer name.
	 * 
	 * @return TextField
	 */
	public TextField getCustomerNameTextfield() {
		TextField customerName = new TextField("Name");
		customerName.setRequired(true);
		customerName.setRequiredError("This field is required");
		customerName.setWidth(Constants.COMMON_FIELD_WIDTH_M);
		return customerName;
	}
	
	/**
	 * Gets a textfield used for displaying customer mobile.
	 * 
	 * @return TextField
	 */
	public TextField getCustomerMobileTextfield() {
		TextField customerMobile = new TextField("Mobile");
		customerMobile.setRequired(true);
		customerMobile.setRequiredError("This field is required");
		customerMobile.setWidth(Constants.COMMON_FIELD_WIDTH_M);
		customerMobile.setImmediate(true);
		customerMobile.setValue(AppData.getUser().getEmployee().getStation().getCountry().getCountryTelCode());
		customerMobile.addValidator(Constants.telValidator);
		return customerMobile;
	}
	
	/**
	 * Gets a textfield used for displaying customer id.
	 * 
	 * @return TextField
	 */
	public TextField getIdNumberTextfield() {
		TextField idNumber = new TextField("Id number");
		idNumber.setWidth(Constants.COMMON_FIELD_WIDTH_M);
		idNumber.setImmediate(true);
		idNumber.addValidator(new StringLengthValidator("Allowed is between 2 and 20 characters.", 2, 20, false));
		return idNumber;
	}
	
	/**
	 * Gets a textfield used for displaying pickup point.
	 * 
	 * @return TextField
	 */
	public TextField getPickupPointTextfield() {
		TextField pickupPoint = new TextField("Pickup point");
		pickupPoint.setWidth(Constants.COMMON_FIELD_WIDTH_M);
		return pickupPoint;
	}
	
	/**
	 * Gets a dropdown that contains routes by date.
	 * 
	 * @return ComboBox
	 */
	private ComboBox getRouteDropdown() {
		final ComboBox route = new ComboBox("Route");
		route.setRequired(true);
		route.setRequiredError("This field is required");

		route.setImmediate(true);
		route.setNullSelectionAllowed(false);
		route.setItemCaptionPropertyId("routeName");
		route.addListener(new ValueChangeListener() {
			@Override
			public void valueChange(ValueChangeEvent event) {
				if(event.getProperty().getValue() != null) {
					Results results = getAvailableSeats((Integer) route.getValue());
					getAvailableSeats(seat, results);
					
					getSubstationsForRoute((Integer) event.getProperty().getValue());
					amount.setReadOnly(false);
					amount.setValue("");
					amount.setReadOnly(true);
				}
			}
		});
		
		return route;
	}
	
	/**
	 * Gets a field to select the departure date. 
	 * 
	 * @return DateField
	 */
	private DateField getDepartureDateField() {
		DateField date = new DateField("Departure date");
		date.setRequired(true);
		date.setRequiredError("This field is required");
		date.setWidth(Constants.COMMON_FIELD_WIDTH_M);
		date.setImmediate(true);
		date.setValue(new Date());
		date.setDateFormat(Constants.DATE_FORMAT_STRING);
		date.setResolution(DateField.RESOLUTION_DAY);
		return date;
	}
	
	/**
	 * Gets a field to select the departure date. 
	 * 
	 * @return DateField
	 */
	private DateField getReturnDateField() {
		DateField date = new DateField("Return date");
		date.setWidth(Constants.COMMON_FIELD_WIDTH_M);
		date.setImmediate(true);
		date.setDateFormat(Constants.DATE_FORMAT_STRING);
		date.setResolution(DateField.RESOLUTION_DAY);
		return date;
	}
	
	/**
	 * Gets a field to select a date. 
	 * 
	 * @return DateField
	 */
	private DateField getTravelDateField() {
		DateField travelDate = new DateField("Travel date");
		travelDate.setRequired(true);
		travelDate.setRequiredError("This field is required");
		travelDate.setWidth(Constants.COMMON_FIELD_WIDTH_M);
		travelDate.setImmediate(true);
		travelDate.addListener(new ValueChangeListener() {
			@Override
			public void valueChange(ValueChangeEvent event) {
				if(event.getProperty().getValue() != null) {
					Date selectedDate = Util.getStartOfADay((Date) event.getProperty().getValue());
					Date today = Util.getStartOfADay(new Date());
					BusApplication app = AppData.getApp();
					if(selectedDate.compareTo(today) == -1) {
						route.setContainerDataSource(null);
					} else {
						ServiceParameter sp = new ServiceParameter(new HashMap<String, String>());
						sp.param.put("startDate", Util.formatDateForDB(Util.getStartOfADay(selectedDate)));
						sp.param.put("endDate", Util.formatDateForDB(Util.getEndOfADay(selectedDate)));
						
						BeanContainer<Integer, Route> container = new BeanContainer<Integer, Route>(Route.class);
						container.setBeanIdProperty("routeId");
						
						DbServicesPrx dbServicesPrx = app.getDbServiceProxy();
						ServiceResult sr = dbServicesPrx.getLoadingsheetRoutesByDate(sp);
						if(sr.status) {
							if(sr.param.get("RECORDS") != null) {
								Results r = Util.getObjectsFromXmlResult(sr.param.get("RECORDS"), Route.class);
								for (Object object : r.getRows()) {
									Route route = (Route) object;
									container.addItem(route.getRouteId(), route);
								}
								route.setContainerDataSource(container);
							} else {
								route.setContainerDataSource(null);
							}
						} else {
							app.showErrorNotification(sr.message);
							route.setContainerDataSource(null);
						}
					}
					route.setValue(null);
					seat.setContainerDataSource(null);
					seat.setValue(null);
					fromSubstation.setContainerDataSource(null);
					fromSubstation.setValue(null);
					toSubstation.setContainerDataSource(null);
					toSubstation.setValue(null);
					amount.setReadOnly(false);
					amount.setValue("");
					amount.setReadOnly(true);
				}
			}
		});
		travelDate.setValue(new Date());
		travelDate.setDateFormat(Constants.DATE_FORMAT_STRING);
		travelDate.setResolution(DateField.RESOLUTION_DAY);
		return travelDate;
	}
	
	/**
	 * Loads data into from and to substation dropdowns that contains the available substation for the selected route.
	 * 
	 */
	private void getSubstationsForRoute(Integer selectedRoute) {
		
		BusApplication app = AppData.getApp();
		
		BeanContainer<Integer, Substation> fromContainer = new BeanContainer<Integer, Substation>(Substation.class);
		fromContainer.setBeanIdProperty("substationId");
		
		BeanContainer<Integer, Substation> toContainer = new BeanContainer<Integer, Substation>(Substation.class);
		toContainer.setBeanIdProperty("substationId");
		
		ServiceParameter sp = new ServiceParameter(new HashMap<String, String>());
		sp.param.put("routeTimeId", selectedRoute.toString());
		
		DbServicesPrx dbServicesPrx = app.getDbServiceProxy();
		ServiceResult sr = dbServicesPrx.getSubstationsByRouteTimeId(sp);
		if(sr.status) {
			if(sr.param.get("RECORDS") != null) {
				Results r = Util.getObjectsFromXmlResult(sr.param.get("RECORDS"), Substation.class);
				
				Substation firstSubstation = (Substation) r.getRows().get(0); // take only the first substation
				fromContainer.addItem(firstSubstation.getSubstationId(), firstSubstation);
				
				for (Object object : r.getRows()) {
					Substation substation = (Substation) object;
					
					//ignore the first substation in the list
					if(firstSubstation.getSubstationId().intValue() != substation.getSubstationId().intValue())
						toContainer.addItem(substation.getSubstationId(), substation);
				}
				fromSubstation.setContainerDataSource(fromContainer);
				fromSubstation.setValue(fromContainer.getItemIds().iterator().next());
				
				toSubstation.setContainerDataSource(toContainer);
			} else {
				app.showErrorNotification("No substations are available for this route");
				fromSubstation.setContainerDataSource(null);
				toSubstation.setContainerDataSource(null);
			}
		} else {
			app.showErrorNotification(sr.message);
			fromSubstation.setContainerDataSource(null);
			toSubstation.setContainerDataSource(null);
		}
		fromSubstation.setItemCaptionPropertyId("name");
		toSubstation.setItemCaptionPropertyId("name");
	}
	
	/**
	 * Gets a value changed listener.
	 *  
	 * @return ValueChangeListener
	 */
	private ValueChangeListener getValueChangeListenerForSubstation() {
		ValueChangeListener listener = new ValueChangeListener() {
			
			@Override
			public void valueChange(ValueChangeEvent event) {
				if(fromSubstation.getValue() != null && toSubstation.getValue() != null) {
					Integer from = (Integer) fromSubstation.getValue();
					Integer to = (Integer) toSubstation.getValue();
					amount.setReadOnly(false);
					
					BusApplication app = AppData.getApp();
					if(from.intValue() != to.intValue()) {
						BeanContainer<Integer, BusFare> container = new BeanContainer<Integer, BusFare>(BusFare.class);
						container.setBeanIdProperty("busFareId");
								
						BusFare busFare = getBusFare(from, to, true);
						if(busFare != null) {
							amount.setItemCaption(busFare.getBusFareId(), Util.formatMoney(busFare.getAmount().toString()) +" "+ busFare.getCurrencyName());
							container.addItem(busFare.getBusFareId(), busFare);
							amount.setContainerDataSource(container);
							amount.setValue(container.getItemIds().iterator().next());
						} else {
							amount.setContainerDataSource(null);
							amount.setValue(null);
						}
					} else {
						ComboBox comboBox = (ComboBox) event.getProperty();
						comboBox.setValue(null);
						app.showErrorNotification("From and to substation can't be the same.");
					}
					amount.setReadOnly(true);
				}
			}
		};
		return listener;
	}
	
	/**
	 * Gets the bus fare based on the from and to substations.
	 * 
	 * @param from
	 * @param to
	 * @param calculateDiscount
	 * 
	 * @return BusFare
	 */
	private BusFare getBusFare(Integer from, Integer to, Boolean calculateDiscount) {
		BusApplication app = AppData.getApp();
		BusFare busFare = null;
		
		ServiceParameter sp = new ServiceParameter(new HashMap<String, String>());
		sp.param.put("fromSubstation", from.toString());
		sp.param.put("toSubstation", to.toString());
		
		DbServicesPrx dbServicesPrx = app.getDbServiceProxy();
		ServiceResult sr = dbServicesPrx.getBusFareByFromToSubstationId(sp);
		if(sr.status) {
			if(sr.param.get("RECORDS") != null) {
				Results r = Util.getObjectsFromXmlResult(sr.param.get("RECORDS"), BusFare.class);
				busFare = (BusFare) r.getRows().get(0);
				
				Temp type = ((BeanItem<Temp>) bookingType.getContainerDataSource().getItem(bookingType.getValue())).getBean();
				if(type.getId() == Constants.BOOKING_TYPE_RETURN) { 
					if(calculateDiscount) {
						BigDecimal discount = calculateDiscount(busFare.getAmount());
						busFare.setAmount(busFare.getAmount().subtract(discount));
					}
				}
				if(booking != null) {
					busFare.setAmount(busFare.getAmount().subtract(booking.getAmount()));
				} 
			} else {
				app.showErrorNotification(Constants.ME_BUSFARE_NOT_FOUND);
			}
		} else {
			app.showErrorNotification(sr.message);
		}
		
		return busFare;
	}
	
	/**
	 * Get the amount that is used as discount based on the bus fare.
	 * 
	 * @param currentFare
	 * 
	 * @return BigDecimal
	 */
	private BigDecimal calculateDiscount(BigDecimal currentFare) {
		BigDecimal result = null;
		
		ServiceParameter sp = new ServiceParameter(new HashMap<String, String>());
		
		DbServicesPrx dbServicesPrx = AppData.getApp().getDbServiceProxy();
		ServiceResult sr = dbServicesPrx.getSystemConfigurations(sp);
		if(sr.status) {
			if(sr.param.get("RECORDS") != null) {
				Results r = Util.getObjectsFromXmlResult(sr.param.get("RECORDS"), SystemConfiguration.class);
				SystemConfiguration systemConfiguration = (SystemConfiguration) r.getRows().iterator().next();
				Double discountInPercentage = new Double(systemConfiguration.getBookingDiscount()) / 100;
				result = currentFare.multiply(new BigDecimal(discountInPercentage));
			}
		}
		return result;
	}
	
	/**
	 * Loads data into the seat dropdown that contains the available seats in results parameter.
	 * 
	 */
	private void getAvailableSeats(ComboBox seatComboBox, Results results) {
		BusApplication app = AppData.getApp();
		
		BeanContainer<Integer, Seat> container = new BeanContainer<Integer, Seat>(Seat.class);
		container.setBeanIdProperty("seatId");
		
		if(results != null) {
			for (Object object : results.getRows()) {
				Seat seat = (Seat) object;
				container.addItem(seat.getSeatId(), seat);
			}
			seatComboBox.setContainerDataSource(container);
		} else {
			app.showErrorNotification("No seats are available for this route");
			seatComboBox.setContainerDataSource(null);
		}
		seatComboBox.setItemCaptionPropertyId("description");
	}
	
	/**
	 * Gets the available seats for the selected route time.
	 * 
	 * @param selectedRouteTime
	 * 
	 * @return Results
	 */
	private Results getAvailableSeats(Integer selectedRouteTime) {
		Results results = null;
		
		BusApplication app = AppData.getApp();
		
		ServiceParameter sp = new ServiceParameter(new HashMap<String, String>());
		sp.param.put("routeTimeId", selectedRouteTime.toString());
		
		DbServicesPrx dbServicesPrx = app.getDbServiceProxy();
		ServiceResult sr = dbServicesPrx.getAvailableSeatsForLoadingsheetByRouteTimeId(sp);
		if(sr.status) {
			if(sr.param.get("RECORDS") != null) {
				results = Util.getObjectsFromXmlResult(sr.param.get("RECORDS"), Seat.class);
			} else {
				app.showErrorNotification("No seats are available for this route");
			}
		} else {
			app.showErrorNotification(sr.message);
		}
		
		return results;
	}
	
	/**
	 * Gets a dropdown used to display all the nationalties.
	 * 
	 * @return ComboBox
	 */
	private ComboBox getNationalityDropdown() {
		final ComboBox nationality = new ComboBox("Nationality");
		nationality.setRequired(true);
		nationality.setRequiredError("This field is required");
		nationality.setWidth(Constants.COMMON_FIELD_WIDTH_M);
		nationality.setNullSelectionAllowed(false);
		
		BusApplication app = AppData.getApp();
		
		BeanContainer<Integer, Country> container = new BeanContainer<Integer, Country>(Country.class);
		container.setBeanIdProperty("countryId");
		
		ServiceParameter sp = new ServiceParameter(new HashMap<String, String>());
		
		DbServicesPrx dbServicesPrx = app.getDbServiceProxy();
		ServiceResult sr = dbServicesPrx.getAllNationalities(sp);
		if(sr.status) {
			if(sr.param.get("RECORDS") != null) {
				Results r = Util.getObjectsFromXmlResult(sr.param.get("RECORDS"), Country.class);
				for (Object object : r.getRows()) {
					Country country = (Country) object;
					container.addItem(country.getCountryId(), country);
				}
				nationality.setContainerDataSource(container);
			} 
		} else {
			app.showErrorNotification(sr.message);
			nationality.setContainerDataSource(null);
		}
		
		nationality.setItemCaptionPropertyId("nationality");
		return nationality;
	}
	
	/**
	 * Gets dropdown that is used to select the number of adults a booking is made for.
	 * 
	 * @return ComboBox
	 */
	private NativeSelect getNrOfAdulsDropdown() {
		NativeSelect nativeSelect = new NativeSelect("Adults");
		nativeSelect.setNullSelectionAllowed(false);
		
		BeanItemContainer<Temp> container = new BeanItemContainer<Temp>(Temp.class);
		for(int i = 0; i < 10; i++ )
			container.addBean(new Temp(i, ""+i));
		
		nativeSelect.setContainerDataSource(container);
		nativeSelect.setValue(container.getItemIds().iterator().next());
		
		return nativeSelect;
	}
	
	/**
	 * Gets dropdown that is used to select the number of children a booking is made for.
	 * 
	 * @return ComboBox
	 */
	private NativeSelect getNrOfChildrenDropdown() {
		NativeSelect nativeSelect = new NativeSelect("Children");
		nativeSelect.setNullSelectionAllowed(false);
		
		BeanItemContainer<Temp> container = new BeanItemContainer<Temp>(Temp.class);
		for(int i = 0; i < 10; i++ )
			container.addBean(new Temp(i, ""+i));
		
		nativeSelect.setContainerDataSource(container);
		nativeSelect.setValue(container.getItemIds().iterator().next());
		
		return nativeSelect;
	}
	
	/**
	 * Gets a text field used for child age.
	 * 
	 * @return TextField
	 */
	private TextField getChildAgeTextField() {
		TextField childAge = new TextField("Child age");
		childAge.setWidth(Constants.COMMON_FIELD_WIDTH_S);
		childAge.setImmediate(true);
		childAge.addValidator(new Validator() {
			
			@Override
			public void validate(Object value) throws InvalidValueException {
				int age = Integer.parseInt(value.toString());
				if(age > Constants.maxChildAge ) {
					throw new InvalidValueException("Invalid child age");
				}
				
			}
			
			@Override
			public boolean isValid(Object value) {
				Boolean result = false; 
				int age = Integer.parseInt(value.toString());
				if(age > Constants.maxChildAge ) {
					//throw new InvalidValueException("Invalid child age");
				} else {
					result = true;
				}
				return result;
			}
		});
		return childAge;
	}
	
	/**
	 * Gets a booking to search for booking.
	 * 
	 * @return Button
	 */
	private Button getFindBookingButton() {
		Button button = new Button("Find booking");
		button.addStyleName("blueButton");
		button.setDisableOnClick(true);
		button.addListener(new Button.ClickListener() {
		    @Override
		    public void buttonClick(ClickEvent event) {
		    	//Boolean checkDates = checkDates();
		    	//Boolean checkFromToSubstation = checkFromToSubstation();
		    	//Boolean checkNrOfPassengers = checkNrOfPassengers();
		    	//Boolean hasBusFare = checkBusFare();
		    	if(checkDates() && checkFromToSubstation() && checkNrOfPassengers() && checkBusFare()) {
		    		BusApplication app = AppData.getApp();
		    		
					app.getMainLayout().getCenter().removeAllComponents();
					app.getMainLayout().getCenter().addComponent(createBookingStep2());
					event.getButton().setEnabled(true);
		    	} else {
		    		event.getButton().setEnabled(true);
		    	}
		    }
		});
		return button;
	}
	
	/**
	 * Checks the departure date and return date of the booking.
	 * 
	 * @return Boolean
	 */
	private Boolean checkDates() {
		Boolean result = true;
		
		Temp type = ((BeanItem<Temp>) bookingType.getContainerDataSource().getItem(bookingType.getValue())).getBean();
		Date dDate = (Date) departureDate.getValue();
		Date now = Util.setDateHourAndMinute(new Date(), 0, 0, false);
		if(dDate == null){
			AppData.getApp().showErrorNotification("Please ensure that departure date is specified.");
			result = false;
		} else if(now.compareTo(dDate) == 1) {
			AppData.getApp().showErrorNotification("Invalid departure date.");
			result = false;
		}
		
		if(type.getId() == Constants.BOOKING_TYPE_RETURN) {
			Date rDate = (Date) returnDate.getValue();
			if(rDate == null) {
				AppData.getApp().showErrorNotification("Please ensure that return date is specified.");
				result = false;
			} else if(dDate.compareTo(rDate) == 1) {
				AppData.getApp().showErrorNotification("Please ensure that departure date is before return date.");
				result = false;
			}
		} 
		return result;
	}
	
	/**
	 * Check the from and to substations dropdown for valid data.
	 * 
	 * @return Boolean
	 */
	private Boolean checkFromToSubstation() {
		Boolean result = false;
		if(fromSubstation.getValue() == null | toSubstation.getValue() == null) {
			AppData.getApp().showErrorNotification("From substation and to substation are both required.");
		} else {
			if(fromSubstation.getValue() == toSubstation.getValue()) {
				AppData.getApp().showErrorNotification(Constants.ME_FROM_TO_SUBSTATIONS_ARE_THE_SAME);
				result = false;
			} else {
				result = true;
			}
		}
		return result;
	}
	
	/**
	 * Checks the adults and children dropdowns for valid data.
	 * 
	 * @return Boolean
	 */
	private Boolean checkNrOfPassengers() {
		Boolean result = true;
		Boolean nrOfAdultsB = ((Temp)nrOfAdults.getValue()).getId() == 0;
		Boolean nrOfChildrenB = ((Temp)nrOfChildren.getValue()).getId() == 0;
		if(nrOfAdultsB && nrOfChildrenB) {
			AppData.getApp().showErrorNotification("At least one passenger is required.");
			result = false;
		}
		return result;
	}
	
	/**
	 * Checks if there is a bus fare can be found for the selected substations.
	 * 
	 * @return
	 */
	private Boolean checkBusFare() {
		Boolean result = true;
		busFare = getBusFare((Integer)fromSubstation.getValue(), (Integer)toSubstation.getValue(), false);
		if(busFare == null)
			result = false;
		return result;
	}
	
	/**
	 * Creates a layout that is used for the second step in the create booking form.
	 * 
	 * @return VerticalLayout
	 */
	private VerticalLayout createBookingStep2() {
		createBookingStep2 = new VerticalLayout();
		createBookingStep2.setSpacing(true);
		
		createBookingStep2.addComponent(new Label("Step 2 of 4"));

		final Temp type = ((BeanItem<Temp>) bookingType.getContainerDataSource().getItem(bookingType.getValue())).getBean();
		final Boolean isReturnBooking = type.getId() == Constants.BOOKING_TYPE_RETURN;
		
		HorizontalLayout departureLayout = new HorizontalLayout();
		departureLayout.setSpacing(true);
		
		final Label availableDepSeatsLabel = new Label();
		availableDepSeatsLabel.setImmediate(true);
		availableDepSeatsLabel.setVisible(false);
		
		Date depDate = (Date)departureDate.getValue();
		departureRoutes = getRouteOptions((Integer)fromSubstation.getValue(), (Integer)toSubstation.getValue(), depDate, true);
		departureRoutes.addListener(new ValueChangeListener() {
			@Override
			public void valueChange(ValueChangeEvent event) {
				if(event.getProperty().getValue() != null) {
					availableDepartureSeats = getAvailableSeats((Integer) departureRoutes.getValue());
					availableDepSeatsLabel.setValue(Constants.ML_AVAILABLE_SEAT_COUNT+ availableDepartureSeats.getRows().size());
					availableDepSeatsLabel.setVisible(true);
				} else {
					availableDepSeatsLabel.setValue("");
					availableDepSeatsLabel.setVisible(false);
				}
			}
		});
		departureLayout.addComponent(departureRoutes);
		departureLayout.addComponent(availableDepSeatsLabel);
		
		Panel depPanel = new Panel();
		depPanel.addStyleName(Runo.PANEL_LIGHT);
		
		Integer dRoutesCount = departureRoutes.getContainerDataSource().size();
		if(dRoutesCount > 0) {
			depPanel.setCaption("Departure, routes found for "+ Util.formatDateWithoutTime(depDate)+":");
			depPanel.addComponent(departureLayout);
			createBookingStep2.addComponent(depPanel);
		} else {
			depPanel.setCaption("No departures routes found for the selected substations.");
			createBookingStep2.addComponent(depPanel);
		}

		if(isReturnBooking) {
			Date retDate = (Date)returnDate.getValue();
			
			HorizontalLayout returnLayout = new HorizontalLayout();
			returnLayout.setSpacing(true);
			
			final Label availableRetSeatsLabel = new Label();
			availableRetSeatsLabel.setImmediate(true);
			availableRetSeatsLabel.setVisible(false);
			
			returnRoutes = getRouteOptions((Integer)fromSubstation.getValue(), (Integer)toSubstation.getValue(), retDate, false);
			returnRoutes.addListener(new ValueChangeListener() {
				@Override
				public void valueChange(ValueChangeEvent event) {
					if(event.getProperty().getValue() != null) {
						availableReturnSeats = getAvailableSeats((Integer) returnRoutes.getValue());
						availableRetSeatsLabel.setValue(Constants.ML_AVAILABLE_SEAT_COUNT+ availableReturnSeats.getRows().size());
						availableRetSeatsLabel.setVisible(true);
					} else {
						availableRetSeatsLabel.setValue("");
						availableRetSeatsLabel.setVisible(false);
					}
				}
			});
			returnLayout.addComponent(returnRoutes);
			returnLayout.addComponent(availableRetSeatsLabel);

			Panel retPanel = new Panel();
			retPanel.addStyleName(Runo.PANEL_LIGHT);
	
			Integer rRoutesCount = returnRoutes.getContainerDataSource().size();
			if(rRoutesCount > 0) {
				retPanel.setCaption("Return, routes found for "+ Util.formatDateWithoutTime(retDate)+":");
				retPanel.addComponent(returnLayout);
				createBookingStep2.addComponent(retPanel);
			} else {
				retPanel.setCaption("No return routes found for the selected substations.");
				createBookingStep2.addComponent(retPanel);
			}
		}
		
		HorizontalLayout buttons = new HorizontalLayout();
		buttons.setSpacing(true);
		createBookingStep2.addComponent(buttons);
		
		Button backToStep1 = getBackButton(createBookingStep1);
		buttons.addComponent(backToStep1);
		
		Button continueToStep3 = new Button("Continue");
		continueToStep3.addStyleName("greenButton");
		continueToStep3.setDisableOnClick(true);
		continueToStep3.addListener(new Button.ClickListener() {
		    @Override
		    public void buttonClick(ClickEvent event) {
		    	BusApplication app = AppData.getApp();
				if(isReturnBooking) {
					if(departureRoutes.getValue() == null)
						app.showErrorNotification(Constants.ME_DEPARTURE_ROUTE_EMPTY);
					else if(returnRoutes.getValue() == null)
						app.showErrorNotification(Constants.ME_RETURN_ROUTE_EMPTY);
					else {
						app.getMainLayout().getCenter().removeAllComponents();
						app.getMainLayout().getCenter().addComponent(createBookingStep3(isReturnBooking));
					}
				} else {
					if(departureRoutes.getValue() == null)
						app.showErrorNotification(Constants.ME_DEPARTURE_ROUTE_EMPTY);
					else {
						app.getMainLayout().getCenter().removeAllComponents();
						app.getMainLayout().getCenter().addComponent(createBookingStep3(isReturnBooking));
					}
				}
				event.getButton().setEnabled(true);
		    }
		});
		
		if(dRoutesCount > 0 )
			buttons.addComponent(continueToStep3);
		
		
		return createBookingStep2;
	}
	
	/**
	 * Creates a layout that is used for the third step in the create booking form.
	 * 
	 * @param isReturnBooking
	 * 
	 * @return VerticalLayout
	 */
	private VerticalLayout createBookingStep3(Boolean isReturnBooking) {
		createBookingStep3 = new VerticalLayout();
		createBookingStep3.setSpacing(true);
		
		createBookingStep3.addComponent(new Label("Step 3 of 4"));
		
		Integer depRoute = (Integer) departureRoutes.getValue();
		Integer retRoute = (Integer) ( isReturnBooking ? returnRoutes.getValue() : null);
		
		passengers = new HashMap<Integer, PassengerDetailForm>();
		Integer passengersCounter = 0;
		
		Temp adultsCounter = ((BeanItem<Temp>) nrOfAdults.getContainerDataSource().getItem(nrOfAdults.getValue())).getBean();
		for (int i = 0; i < adultsCounter.getId(); i++) {
			PassengerDetailForm passengerDetailForm = new PassengerDetailForm(depRoute, retRoute, false);
			passengers.put(passengersCounter, passengerDetailForm);
			createBookingStep3.addComponent(passengerDetailForm);
			passengersCounter++;
		}
		
		Temp childrenCounter = ((BeanItem<Temp>) nrOfChildren.getContainerDataSource().getItem(nrOfChildren.getValue())).getBean();
		for (int i = 0; i < childrenCounter.getId(); i++) {
			PassengerDetailForm passengerDetailForm = new PassengerDetailForm(depRoute, retRoute, true);
			passengers.put(passengersCounter, passengerDetailForm);
			createBookingStep3.addComponent(passengerDetailForm);
			passengersCounter++;
		}
		
		HorizontalLayout buttons = new HorizontalLayout();
		buttons.setSpacing(true);
		createBookingStep3.addComponent(buttons);
		
		Button backToStep2 = getBackButton(createBookingStep2);
		buttons.addComponent(backToStep2);
		
		Button continueToStep4Btn = new Button("Continue");
		continueToStep4Btn.addStyleName("greenButton");
		continueToStep4Btn.setDisableOnClick(true);
		continueToStep4Btn.addListener(new Button.ClickListener() {
		    @Override
		    public void buttonClick(ClickEvent event) {
		    	if(validatePassengerDetailForms()) {
		    		BusApplication app = AppData.getApp();
		    		
					app.getMainLayout().getCenter().removeAllComponents();
					app.getMainLayout().getCenter().addComponent(createBookingStep4());
		    	}
				event.getButton().setEnabled(true);
		    }
		});
		buttons.addComponent(continueToStep4Btn);
		
		return createBookingStep3;
	}
	
	/**
	 * Validates the passenger details forms in list passengers.
	 * 
	 * @return Boolean
	 */
	private Boolean validatePassengerDetailForms() {
		Boolean result = false;
		BusApplication app = AppData.getApp();
		List<Boolean> booleanList = new ArrayList<Boolean>();
		
		List<Seat> depSeats = new ArrayList<Seat>();
		List<Seat> retSeats = new ArrayList<Seat>();
    	for (PassengerDetailForm p : passengers.values()) {
			booleanList.add(p.isValid());
			if(p.departureSeat != null && p.departureSeat.getValue() != null) {
				Seat seat = ((BeanItem<Seat>) p.departureSeat.getContainerDataSource().getItem(p.departureSeat.getValue())).getBean();
				depSeats.add(seat);
			}
			
			if(p.returnSeat != null && p.returnSeat.getValue() != null) {
				Seat seat = ((BeanItem<Seat>) p.returnSeat.getContainerDataSource().getItem(p.returnSeat.getValue())).getBean();
				retSeats.add(seat);
			}
		}
    	
    	Seat tempSeat = null;
    	for (Seat seat : depSeats) {
    		List<Seat> tSeats = new ArrayList<Seat>();
    		tSeats.addAll(depSeats);
    		tSeats.remove(seat);
    		if(tSeats.contains(seat))
    			tempSeat = seat;
		}
    	
    	for (Seat seat : retSeats) {
    		List<Seat> tSeats = new ArrayList<Seat>();
    		tSeats.addAll(retSeats);
    		tSeats.remove(seat);
    		if(tSeats.contains(seat))
    			tempSeat = seat;
		}
    	
    	if(booleanList.contains(false))
    		app.showErrorNotification(Constants.ME_FORM_FIELDS_REQUIRED);
    	else if(tempSeat != null)
    		app.showErrorNotification(Constants.ME_OCCUPIED_SEAT_SELECTED+ tempSeat.getDescription());
    	else
    		result = true;
    	
		return result;
	}
	
	/**
	 * Creates a layout that is used for the fourth step in the create booking form.
	 * 
	 * @return VerticalLayout
	 */
	private VerticalLayout createBookingStep4() {
		createBookingStep4 = new VerticalLayout();
		createBookingStep4.setSpacing(true);
		
		createBookingStep4.addComponent(new Label("Step 4 of 4"));
		
		Temp type = ((BeanItem<Temp>) bookingType.getContainerDataSource().getItem(bookingType.getValue())).getBean();
		Boolean isReturnBooking = type.getId() == Constants.BOOKING_TYPE_RETURN;
		
		Temp nrOfAdu = ((BeanItem<Temp>) nrOfAdults.getContainerDataSource().getItem(nrOfAdults.getValue())).getBean();
		Temp nrOfChi = ((BeanItem<Temp>) nrOfChildren.getContainerDataSource().getItem(nrOfChildren.getValue())).getBean();
		
		Substation from = ((BeanItem<Substation>) fromSubstation.getContainerDataSource().getItem(fromSubstation.getValue())).getBean();
		Substation to = ((BeanItem<Substation>) toSubstation.getContainerDataSource().getItem(toSubstation.getValue())).getBean();
		Route depRoute = ((BeanItem<Route>) departureRoutes.getContainerDataSource().getItem(departureRoutes.getValue())).getBean();
		
		BigDecimal discount = null;
		String depDate = Util.formatDateWithoutTime((Date)departureDate.getValue());

		String layoutContent = "<table>"+
								"	<tr>"+
								"		<td><b>Departure:</b></td>"+
								"		<td> "+ from.getName() +" - "+ to.getName() +" "+ depDate +" "+ depRoute.getDepartureTime() +" "+ depRoute.getAmpm() +" </td>"+
								"	</tr>";
		if(isReturnBooking) {
			Route retRoute = ((BeanItem<Route>) returnRoutes.getContainerDataSource().getItem(returnRoutes.getValue())).getBean();
			String retDate = Util.formatDateWithoutTime((Date)returnDate.getValue());
			layoutContent +=	"	<tr>"+
								"		<td><b>Return:</b></td>"+
								"		<td> "+ to.getName() +" - "+ from.getName() +" "+ retDate +" "+ retRoute.getDepartureTime() +" "+ retRoute.getAmpm() +" </td>"+
								"	</tr>";
		}
		if((nrOfAdu.getId() + nrOfChi.getId()) > 1) {
			String adults = nrOfAdu.getId() != 0 ? "Adults: "+ nrOfAdu.getId() : null;
			String childeren = nrOfChi.getId() != 0 ? "Children: "+ nrOfChi.getId() : null;
			String pass = "";
			if(adults != null) {
				pass = adults;
				if(childeren != null)
					pass += " and "+ childeren;
			} else {
				pass = childeren;
			}
			layoutContent +=	"	<tr>"+
								"		<td><b>Passengers:</b></td>"+
								"		<td> "+ pass +" </td>"+
								"	</tr>";
		}
		layoutContent +=		"	<tr>"+
								"		<td><b>Fare:</b></td>"+
								"		<td align='right'> "+ Util.formatMoney(busFare.getAmount().toString()) +" </td>"+
								"		<td> </td>"+
								"		<td> "+ busFare.getCurrencyName() +" </td>"+
								"	</tr>";
		if(isReturnBooking) {
			discount = calculateDiscount(busFare.getAmount());
			layoutContent +=	"	<tr>"+
								"		<td><b>Discount:</b></td>"+
								"		<td align='right'> "+ Util.formatMoney(discount.toString()) +"</td>"+
								"		<td> - </td>"+
								"		<td> "+ busFare.getCurrencyName() +" </td>"+
								"	</tr>";
		}
		BigDecimal totalPP = discount != null ? busFare.getAmount().subtract(discount) : busFare.getAmount();
		layoutContent +=		"	<tr class='bottom'>"+
								"		<td colspan='4'></td>"+
								"	</tr>"+
								"	<tr>"+
								"		<td><b>Total p.p:</b></td>"+
								"		<td align='right'> "+ Util.formatMoney(totalPP.toString()) +"</td>"+
								"		<td> </td>"+
								"		<td> "+ busFare.getCurrencyName() +" </td>"+
								"	</tr>";
		if((nrOfAdu.getId() + nrOfChi.getId()) > 1) {
			Integer totalPassengers = nrOfAdu.getId() + nrOfChi.getId();
			layoutContent +=		"	<tr>"+
								"		<td></td>"+
								"		<td align='right'> "+ totalPassengers +" </td>"+
								"		<td> x </td>"+
								"		<td> "+ busFare.getCurrencyName() +" </td>"+
								"	</tr>"+
								"	<tr class='bottom'>"+
								"		<td colspan='4'></td>"+
								"	</tr>"+
								"	<tr>"+
								"		<td><b>Total:</b></td>"+
								"		<td align='right'> "+ Util.formatMoney(totalPP.multiply(new BigDecimal(totalPassengers)).toString()) +"</td>"+
								"		<td> </td>"+
								"		<td> "+ busFare.getCurrencyName() +" </td>"+
								"	</tr>";
		}
		layoutContent += 		"</table>";
		
		createBookingStep4.addComponent(new Label(layoutContent, Label.CONTENT_XHTML));
		
		HorizontalLayout buttons = new HorizontalLayout();
		buttons.setSpacing(true);
		createBookingStep4.addComponent(buttons);
		
		final Button backToStep3 = getBackButton(createBookingStep3);
		buttons.addComponent(backToStep3);
		
		Button saveBookingBtn = new Button("Save booking");
		final Button printBtn = new Button("Print");
		
		saveBookingBtn.addStyleName("blueButton");
		saveBookingBtn.setDisableOnClick(true);
		saveBookingBtn.addListener(new Button.ClickListener() {
		    @Override
		    public void buttonClick(ClickEvent event) {
		    	BusApplication app = AppData.getApp();
		    	
		    	Temp type = ((BeanItem<Temp>) bookingType.getContainerDataSource().getItem(bookingType.getValue())).getBean();
				Boolean isReturnBooking = type.getId() == Constants.BOOKING_TYPE_RETURN;
				
				Substation from = ((BeanItem<Substation>) fromSubstation.getContainerDataSource().getItem(fromSubstation.getValue())).getBean();
	    		Substation to = ((BeanItem<Substation>) toSubstation.getContainerDataSource().getItem(toSubstation.getValue())).getBean();				
				Route depRoute = ((BeanItem<Route>) departureRoutes.getContainerDataSource().getItem(departureRoutes.getValue())).getBean();
		    	
				BigDecimal discount = calculateDiscount(busFare.getAmount());
				BigDecimal totalPP = discount != null ? busFare.getAmount().subtract(discount) : busFare.getAmount();
				
				List<String> depTime = Arrays.asList(depRoute.getDepartureTime().split(":"));
	    		List<String> depRepTime = Arrays.asList(depRoute.getReportingTime().split(":"));
	    		
	    		Date depTravelDate = Util.setDateHourAndMinute((Date) departureDate.getValue(), Integer.parseInt(depTime.get(0)), Integer.parseInt(depTime.get(1)), "pm".equalsIgnoreCase(depRoute.getAmpm()));
	    		Date depReportingDate = Util.setDateHourAndMinute((Date) departureDate.getValue(), Integer.parseInt(depRepTime.get(0)), Integer.parseInt(depRepTime.get(1)), "pm".equalsIgnoreCase(depRoute.getAmpm()));
		    	
	    		ServiceParameter sp = new ServiceParameter(new TreeMap<String, String>());
	    		
	    		Integer bookingCounter = 0;
	    		
	    		for (PassengerDetailForm p : passengers.values()) {
	    			String booking = "";
	    			
		    		booking += "userId"+ Constants.itemValueSeparator + AppData.getUser().getUserId().toString();
		    		booking += Constants.elementSeparator +"name"+ Constants.itemValueSeparator + p.customerName.getValue().toString();
					booking += Constants.elementSeparator +"mobile"+ Constants.itemValueSeparator + p.customerMobile.getValue().toString();
					booking += Constants.elementSeparator +"nationality"+ Constants.itemValueSeparator + p.nationality.getValue().toString();
					booking += Constants.elementSeparator +"idNumber"+ Constants.itemValueSeparator + p.idNumber.getValue().toString();
					booking += Constants.elementSeparator +"childAge"+ Constants.itemValueSeparator + p.childAge.getValue().toString();
					booking += Constants.elementSeparator +"amount"+ Constants.itemValueSeparator + totalPP.toString();
					booking += Constants.elementSeparator +"currencyName"+ Constants.itemValueSeparator + busFare.getCurrencyName();
					booking += Constants.elementSeparator +"pickupPoint"+ Constants.itemValueSeparator + p.pickupPoint.getValue().toString();
					booking += Constants.elementSeparator +"bookingAction"+ Constants.itemValueSeparator + Constants.BOOKING_ACTION_BOOK;
					booking += Constants.elementSeparator +"bookingStatus"+ Constants.itemValueSeparator + Constants.BOOKING_STATUS_ACTIVE;
					booking += Constants.elementSeparator +"seatStatus"+ Constants.itemValueSeparator + Constants.SEAT_STATUS_UNAVAILABLE;
					booking += Constants.elementSeparator +"isOneWay"+ Constants.itemValueSeparator + (type.getId() == Constants.BOOKING_TYPE_ONE_WAY ? "1" : "0");

					Seat depSeat = ((BeanItem<Seat>) p.departureSeat.getContainerDataSource().getItem(p.departureSeat.getValue())).getBean();
					
					booking += Constants.elementSeparator +"travelDate"+ Constants.itemValueSeparator + Util.formatDateForDB(depTravelDate);
					booking += Constants.elementSeparator +"reportingDate"+ Constants.itemValueSeparator + Util.formatDateForDB(depReportingDate);
					booking += Constants.elementSeparator +"departureTime"+ Constants.itemValueSeparator + depRoute.getDepartureTime() +" "+ depRoute.getAmpm();
					booking += Constants.elementSeparator +"reportingTime"+ Constants.itemValueSeparator + depRoute.getReportingTime() +" "+ depRoute.getAmpm();
					booking += Constants.elementSeparator +"loadingsheetId"+ Constants.itemValueSeparator + depRoute.getLoadingsheetId().toString();
					booking += Constants.elementSeparator +"seatId"+ Constants.itemValueSeparator + p.departureSeat.getValue().toString();
					booking += Constants.elementSeparator +"seatName"+ Constants.itemValueSeparator + depSeat.getDescription();
					booking += Constants.elementSeparator +"fromSubstation"+ Constants.itemValueSeparator + fromSubstation.getValue().toString();
					booking += Constants.elementSeparator +"toSubstation"+ Constants.itemValueSeparator + toSubstation.getValue().toString();
					booking += Constants.elementSeparator +"fromSubstationName"+ Constants.itemValueSeparator + from.getName();
					booking += Constants.elementSeparator +"toSubstationName"+ Constants.itemValueSeparator + to.getName();
		    		
					sp.param.put(bookingCounter.toString(), booking);
		    		
		    		if(isReturnBooking) {
		    			bookingCounter++;
		    			String returnBooking = "";
		    			
			    		returnBooking += "userId"+ Constants.itemValueSeparator + AppData.getUser().getUserId().toString();
			    		returnBooking += Constants.elementSeparator +"name"+ Constants.itemValueSeparator + p.customerName.getValue().toString();
						returnBooking += Constants.elementSeparator +"mobile"+ Constants.itemValueSeparator + p.customerMobile.getValue().toString();
						returnBooking += Constants.elementSeparator +"nationality"+ Constants.itemValueSeparator + p.nationality.getValue().toString();
						returnBooking += Constants.elementSeparator +"idNumber"+ Constants.itemValueSeparator + p.idNumber.getValue().toString();
						returnBooking += Constants.elementSeparator +"childAge"+ Constants.itemValueSeparator + p.childAge.getValue().toString();
						returnBooking += Constants.elementSeparator +"amount"+ Constants.itemValueSeparator + totalPP.toString();
						returnBooking += Constants.elementSeparator +"currencyName"+ Constants.itemValueSeparator + busFare.getCurrencyName();
						returnBooking += Constants.elementSeparator +"pickupPoint"+ Constants.itemValueSeparator + p.pickupPoint.getValue().toString();
						returnBooking += Constants.elementSeparator +"bookingAction"+ Constants.itemValueSeparator + Constants.BOOKING_ACTION_BOOK;
						returnBooking += Constants.elementSeparator +"bookingStatus"+ Constants.itemValueSeparator + Constants.BOOKING_STATUS_ACTIVE;
						returnBooking += Constants.elementSeparator +"seatStatus"+ Constants.itemValueSeparator + Constants.SEAT_STATUS_UNAVAILABLE;
						returnBooking += Constants.elementSeparator +"isOneWay"+ Constants.itemValueSeparator + (type.getId() == Constants.BOOKING_TYPE_ONE_WAY ? "1" : "0");
			    		
			    		Route retRoute = ((BeanItem<Route>) returnRoutes.getContainerDataSource().getItem(returnRoutes.getValue())).getBean();
			    		Seat retSeat = ((BeanItem<Seat>) p.returnSeat.getContainerDataSource().getItem(p.returnSeat.getValue())).getBean();
			    		
			    		List<String> retTime = Arrays.asList(retRoute.getDepartureTime().split(":"));
			    		List<String> retRepTime = Arrays.asList(retRoute.getReportingTime().split(":"));
			    		
			    		Date retTravelDate = Util.setDateHourAndMinute((Date) returnDate.getValue(), Integer.parseInt(retTime.get(0)), Integer.parseInt(retTime.get(1)), "pm".equalsIgnoreCase(retRoute.getAmpm()));
			    		Date retReportingDate = Util.setDateHourAndMinute((Date) returnDate.getValue(), Integer.parseInt(retRepTime.get(0)), Integer.parseInt(retRepTime.get(1)), "pm".equalsIgnoreCase(retRoute.getAmpm()));
			    		
			    		returnBooking += Constants.elementSeparator +"travelDate"+ Constants.itemValueSeparator + Util.formatDateForDB(retTravelDate);
						returnBooking += Constants.elementSeparator +"reportingDate"+ Constants.itemValueSeparator + Util.formatDateForDB(retReportingDate);
						returnBooking += Constants.elementSeparator +"departureTime"+ Constants.itemValueSeparator + retRoute.getDepartureTime() +" "+ retRoute.getAmpm();
						returnBooking += Constants.elementSeparator +"reportingTime"+ Constants.itemValueSeparator + retRoute.getReportingTime() +" "+ retRoute.getAmpm();
						returnBooking += Constants.elementSeparator +"loadingsheetId"+ Constants.itemValueSeparator + retRoute.getLoadingsheetId().toString();
						returnBooking += Constants.elementSeparator +"seatId"+ Constants.itemValueSeparator + p.returnSeat.getValue().toString();
						returnBooking += Constants.elementSeparator +"seatName"+ Constants.itemValueSeparator + retSeat.getDescription();
						returnBooking += Constants.elementSeparator +"fromSubstation"+ Constants.itemValueSeparator + toSubstation.getValue().toString();
						returnBooking += Constants.elementSeparator +"toSubstation"+ Constants.itemValueSeparator + fromSubstation.getValue().toString();
						returnBooking += Constants.elementSeparator +"fromSubstationName"+ Constants.itemValueSeparator + to.getName();
						returnBooking += Constants.elementSeparator +"toSubstationName"+ Constants.itemValueSeparator + from.getName();
			    		
						sp.param.put(bookingCounter.toString(), returnBooking);
		    		}
		    		bookingCounter++;
	    		}
	    		
		    	DbServicesPrx dbServicesPrx = app.getDbServiceProxy();
	    		ServiceResult sr = dbServicesPrx.saveBookings(sp);
	    		
	    		if(sr.status) {
	    			app.showNotification(Constants.MN_SUCCESSFULLY_SAVED);
	    			bookingResult = sr.param;
	    			printBtn.setEnabled(true);
	    			backToStep3.setEnabled(false);
	    		} else {
	    			app.showErrorNotification(sr.message);
	    			event.getButton().setEnabled(true);
	    		}
		    }
		});
		buttons.addComponent(saveBookingBtn);
		
		printBtn.setEnabled(false);
		printBtn.addStyleName("blueButton");
		printBtn.setDisableOnClick(true);
		printBtn.addListener(new Button.ClickListener() {
		    @Override
		    public void buttonClick(ClickEvent event) {
		    	if(bookingResult != null) {
		    		Window printWindow = getPrintWindow(event.getButton());
		    		
		    		Boolean notFirstPage = false;
		    		
		    		for (String key : bookingResult.keySet()) {
		    			Map<String, String> booking = new HashMap<String, String>();
		    			
		    			for(String element : bookingResult.get(key).split(Constants.elementSeparator)) {
		    				String id = Arrays.asList(element.split(Constants.itemValueSeparator)).get(0);
		    				
		    				if(element.split("====").length > 1) {
		    					String value = Arrays.asList(element.split(Constants.itemValueSeparator)).get(1);
			    				booking.put(id, value);
		    				} else {
		    					booking.put(id, null);
		    				}
		    			}
		    			
		    			String pickupPoint = "";
		    			if(booking.get("pickupPoint") != null && !"".equalsIgnoreCase(booking.get("pickupPoint")))
		    				pickupPoint = "(Pickup: "+ booking.get("pickupPoint") +")";
		    			
		    			String childAge = "";
		    			if(booking.get("childAge") != null && !"".equalsIgnoreCase(booking.get("childAge")))
		    				childAge +=
		    					"		<td colspan='2'>" +
		    					"			<div>"+ "Child age: "+ booking.get("childAge") +"</div>" +
		    					"		</td>";
		    			String pageBreak = "";
		    			if(bookingResult.size() > 1 && notFirstPage ) // start new page
		    				pageBreak = "<div style='page-break-before: always;'></div>"; 
		    			else
		    				notFirstPage = true;
		    			
		    			String printLayout = pageBreak +
		    					"<table style='border-spacing: 0; border-collapse: collapse;'>" +
		    					"	<tr class='top bottom row'>" +
		    					"		<td>" +
		    					"			<div>Ticket no:</div>" +
		    					"			<div>Name:</div>" +
		    					"		</td>" +
		    					"		<td colspan='4'>" +
		    					"			<div>"+ booking.get("bookingId") +"</div>" +
		    					"			<div>"+ booking.get("name") +"</div>" +
		    					"		</td>" +
		    					"	</tr>" +
		    					"	<tr class='top left row'>" +
		    					"		<td>From:</td>" +
		    					"		<td>To:</td>" +
		    					"		<td>Seat no:</td>" +
		    					"		<td>Id no:</td>" +
		    					"		<td>Mobile no:</td>" +
		    					"	</tr>" +
		    					"	<tr class='bottom left row'>" +
		    					"		<td style='width: 150px'>" +
		    					"			<div>"+ booking.get("fromSubstationName") +"</div>" +
		    					"			"+ pickupPoint +
		    					"		</td>" +
		    					"		<td style='width: 150px'>"+ booking.get("toSubstationName") +"</td>" +
		    					"		<td style='width: 100px'>"+ booking.get("seatName") +"</td>" +
		    					"		<td style='width: 100px'>"+ booking.get("idNumber") +"</td>" +
		    					"		<td style='width: 100px'>"+ booking.get("mobile") +"</td>" +
		    					"	</tr>" +
		    					"	<tr class='top left row'>" +
		    					"		<td>Date of issue:</td>" +
		    					"		<td>Date of travel:</td>" +
		    					"		<td>" +
		    					"			<div>"+ "Fair paid ("+ booking.get("currencyName") +"):" +"</div>" +
		    					"		</td>" +
		    					"		<td colspan='2'>" +
		    					"			"+ childAge +
		    					"		</td>" +
		    					"	</tr>" +
		    					"	<tr class='bottom left row'>" +
		    					"		<td>"+ Util.formatDate(booking.get("actionDate")) +"</td>" +
		    					"		<td>"+ Util.formatDateWithoutTime(booking.get("travelDate")) +"</td>" +
		    					"		<td>"+ Util.formatMoney(booking.get("amount")) +"</td>" +
		    					"		<td colspan='2'></td>" +
		    					"	</tr>" +
		    					"		<tr class='top left row'>" +
		    					"		<td>Reporting time:</td>" +
		    					"		<td>Departure time:</td>" +
		    					"		<td colspan='3'>Served by:</td>" +
		    					"	</tr>" +
		    					"	<tr class='bottom left row'>" +
		    					"		<td>"+ booking.get("reportingTime") +"</td>" +
		    					"		<td>"+ booking.get("departureTime") +"</td>" +
		    					"		<td colspan='3'>"+ AppData.getUser().toString() +"</td>" +
		    					"	</tr>" +
		    					"</table>" +
		    					"<div style='font-weight: bold;'>Cash once paid is NOT refundable or transferable. </div>";
		    			
		    			printWindow.addComponent(new Label(printLayout, Label.CONTENT_XHTML)); 
		    			
		    			/*CustomLayout printBookingLayout = new CustomLayout("printBooking");
		    			
		    			if(bookingResult.size() > 1 && notFirstPage ) // start new page
		    				printBookingLayout.addComponent(new Label("<div class='pageBreak'></div>", Label.CONTENT_XHTML)); 
		    			else
		    				notFirstPage = true;
		    			
				        printBookingLayout.addComponent(new Label(booking.get("bookingId")), "ticketNo");
				        printBookingLayout.addComponent(new Label(booking.get("name")), "name");
				        printBookingLayout.addComponent(new Label(booking.get("fromSubstationName")), "from");
				        if(booking.get("pickupPoint") != null && !"".equalsIgnoreCase(booking.get("pickupPoint")))
				        	printBookingLayout.addComponent(new Label("(Pickup: "+ booking.get("pickupPoint") +")"), "pickupPoint");
				        printBookingLayout.addComponent(new Label(booking.get("toSubstationName")), "to");
				        printBookingLayout.addComponent(new Label(booking.get("seatName")), "seat");
				        printBookingLayout.addComponent(new Label(booking.get("idNumber")), "idNo");
				        printBookingLayout.addComponent(new Label(booking.get("mobile")), "mobileNo");
				        printBookingLayout.addComponent(new Label("Fair paid ("+ booking.get("currencyName") +"):"), "currencyName");
				        if(booking.get("childAge") != null && !"".equalsIgnoreCase(booking.get("childAge")))
				        	printBookingLayout.addComponent(new Label("Child age: "+ booking.get("childAge")), "childAge");
				        printBookingLayout.addComponent(new Label(Util.formatDate(booking.get("actionDate"))), "issueDate");
				        printBookingLayout.addComponent(new Label(Util.formatDateWithoutTime(booking.get("travelDate"))), "travelDate");
				        printBookingLayout.addComponent(new Label(Util.formatMoney(booking.get("amount"))), "amount");
				        printBookingLayout.addComponent(new Label(booking.get("reportingTime")), "reportingTime");
				        printBookingLayout.addComponent(new Label(booking.get("departureTime")), "departureTime");
				        printBookingLayout.addComponent(new Label(AppData.getUser().toString()), "userFullName");
				        // Have some content to print
				        printWindow.addComponent(printBookingLayout);*/
		    		}
		    		event.getButton().setEnabled(true);
		    	}
		    }
		});
		buttons.addComponent(printBtn);
		
		return createBookingStep4;
	}
	
	private void tmp() {
		Button saveBookingBtn = new Button("Save booking");
		final Button printBtn = new Button("Print");
		
		saveBookingBtn.addStyleName("blueButton");
		saveBookingBtn.setDisableOnClick(true);
		saveBookingBtn.addListener(new Button.ClickListener() {
		    @Override
		    public void buttonClick(ClickEvent event) {
		    	BusApplication app = AppData.getApp();
		    	
		    	Temp type = ((BeanItem<Temp>) bookingType.getContainerDataSource().getItem(bookingType.getValue())).getBean();
				Boolean isReturnBooking = type.getId() == Constants.BOOKING_TYPE_RETURN;
				
				Route depRoute = ((BeanItem<Route>) departureRoutes.getContainerDataSource().getItem(departureRoutes.getValue())).getBean();
		    	
				BigDecimal discount = calculateDiscount(busFare.getAmount());
				BigDecimal totalPP = discount != null ? busFare.getAmount().subtract(discount) : busFare.getAmount();
				
				List<String> depTime = Arrays.asList(depRoute.getDepartureTime().split(":"));
	    		List<String> depRepTime = Arrays.asList(depRoute.getReportingTime().split(":"));
	    		
	    		Date depTravelDate = Util.setDateHourAndMinute((Date) departureDate.getValue(), Integer.parseInt(depTime.get(0)), Integer.parseInt(depTime.get(1)), "pm".equalsIgnoreCase(depRoute.getAmpm()));
	    		Date depReportingDate = Util.setDateHourAndMinute((Date) departureDate.getValue(), Integer.parseInt(depRepTime.get(0)), Integer.parseInt(depRepTime.get(1)), "pm".equalsIgnoreCase(depRoute.getAmpm()));
		    	
	    		ServiceParameter sp = new ServiceParameter(new HashMap<String, String>());
	    		
	    		Map<Integer, Object> bookings = new HashMap<Integer, Object>();
	    		int bookingCounter = 0;
	    		
	    		for (int i = 0; i < passengers.size(); i++) {
	    			PassengerDetailForm p = passengers.get(i);
	    			
	    			Map<String, String> booking = new HashMap<String, String>();
	    			
		    		booking.put("userId", AppData.getUser().getUserId().toString());
		    		booking.put("name", p.customerName.getValue().toString());
		    		booking.put("mobile", p.customerMobile.getValue().toString());
		    		booking.put("nationality", p.nationality.getValue().toString());
		    		booking.put("idNumber", p.idNumber.getValue().toString());
		    		booking.put("childAge", p.childAge.getValue().toString());
		    		booking.put("amount", totalPP.toString());
		    		booking.put("currencyName", busFare.getCurrencyName());
		    		booking.put("pickupPoint", p.pickupPoint.getValue().toString());
		    		booking.put("bookingAction", ""+Constants.BOOKING_ACTION_BOOK);
		    		booking.put("bookingStatus", ""+Constants.BOOKING_STATUS_ACTIVE);
		    		booking.put("seatStatus", ""+Constants.SEAT_STATUS_UNAVAILABLE);
		    		booking.put("isOneWay", (type.getId() == Constants.BOOKING_TYPE_ONE_WAY ? "1" : "0"));
		    		
		    		booking.put("travelDate", Util.formatDateForDB(depTravelDate));
		    		booking.put("reportingDate", Util.formatDateForDB(depReportingDate));
		    		booking.put("loadingsheetId", depRoute.getLoadingsheetId().toString());
		    		booking.put("seatId", p.departureSeat.getValue().toString());
		    		booking.put("fromSubstation", fromSubstation.getValue().toString());
		    		booking.put("toSubstation", toSubstation.getValue().toString());
		    		
		    		bookings.put(bookingCounter, booking);
		    		
		    		if(isReturnBooking) {
		    			bookingCounter++;
		    			
		    			Map<String, String> returnBooking = new HashMap<String, String>();
		    			
			    		returnBooking.put("userId", AppData.getUser().getUserId().toString());
			    		returnBooking.put("name", p.customerName.getValue().toString());
			    		returnBooking.put("mobile", p.customerMobile.getValue().toString());
			    		returnBooking.put("nationality", p.nationality.getValue().toString());
			    		returnBooking.put("idNumber", p.idNumber.getValue().toString());
			    		returnBooking.put("childAge", p.childAge.getValue().toString());
			    		returnBooking.put("amount", totalPP.toString());
			    		returnBooking.put("currencyName", busFare.getCurrencyName());
			    		returnBooking.put("pickupPoint", p.pickupPoint.getValue().toString());
			    		returnBooking.put("bookingAction", ""+Constants.BOOKING_ACTION_BOOK);
			    		returnBooking.put("bookingStatus", ""+Constants.BOOKING_STATUS_ACTIVE);
			    		returnBooking.put("seatStatus", ""+Constants.SEAT_STATUS_UNAVAILABLE);
			    		returnBooking.put("isOneWay", (type.getId() == Constants.BOOKING_TYPE_ONE_WAY ? "1" : "0"));
			    		
			    		Route retRoute = ((BeanItem<Route>) returnRoutes.getContainerDataSource().getItem(returnRoutes.getValue())).getBean();
			    		
			    		List<String> retTime = Arrays.asList(retRoute.getDepartureTime().split(":"));
			    		List<String> retRepTime = Arrays.asList(retRoute.getReportingTime().split(":"));
			    		
			    		Date retTravelDate = Util.setDateHourAndMinute((Date) returnDate.getValue(), Integer.parseInt(retTime.get(0)), Integer.parseInt(retTime.get(1)), "pm".equalsIgnoreCase(retRoute.getAmpm()));
			    		Date retReportingDate = Util.setDateHourAndMinute((Date) returnDate.getValue(), Integer.parseInt(retRepTime.get(0)), Integer.parseInt(retRepTime.get(1)), "pm".equalsIgnoreCase(retRoute.getAmpm()));
			    		
			    		returnBooking.put("travelDate", Util.formatDateForDB(retTravelDate));
			    		returnBooking.put("reportingDate", Util.formatDateForDB(retReportingDate));
			    		returnBooking.put("loadingsheetId", retRoute.getLoadingsheetId().toString());
			    		returnBooking.put("seatId", p.returnSeat.getValue().toString());
			    		returnBooking.put("fromSubstation", toSubstation.getValue().toString());
			    		returnBooking.put("toSubstation", fromSubstation.getValue().toString());
			    		
			    		bookings.put(bookingCounter, returnBooking);
		    		}
		    		bookingCounter++;
	    		}
	    		
	    		sp.param.put("bookings", bookings.toString());
	    		
		    	DbServicesPrx dbServicesPrx = app.getDbServiceProxy();
	    		ServiceResult sr = dbServicesPrx.saveBookings(sp);
	    		
	    		if(sr.status) {
	    			app.showNotification(Constants.MN_SUCCESSFULLY_SAVED);
	    			//bookingId = sr.param.get("bookingId");
	    			//actionDate = Util.formatDate(sr.param.get("actionDate"));
	    			printBtn.setEnabled(true);
	    			//backToStep3.setEnabled(false);
	    		} else {
	    			app.showErrorNotification(sr.message);
	    			event.getButton().setEnabled(true);
	    		}
		    }
		});
	}
	
	/**
	 * <code>PassengerDetailForm</code> is used to display the details of the passengers.
	 * 
	 * @author Abdullahi
	 *
	 */
	private class PassengerDetailForm extends Form {
		ComboBox departureSeat = null;
		ComboBox returnSeat = null;
		TextField customerName = null;
		TextField customerMobile = null;
		ComboBox nationality = null;
		TextField idNumber = null;
		TextField pickupPoint = null;
		TextField childAge = null;
		
		public PassengerDetailForm(Integer departureRoute, Integer returnRoute, Boolean isChild) {
			this.departureSeat = getSeatDropdown("Dep seat");
			this.returnSeat = getSeatDropdown("Ret seat");
			this.customerName = getCustomerNameTextfield();
			this.customerMobile = getCustomerMobileTextfield();
			this.nationality = getNationalityDropdown();
			this.idNumber = getIdNumberTextfield();
			this.pickupPoint = getPickupPointTextfield();
			this.childAge = getChildAgeTextField();
			
			getAvailableSeats(this.departureSeat, availableDepartureSeats);
			
			HorizontalLayout layout = new HorizontalLayout();
			layout.setSpacing(true);
			setLayout(layout);
			
			addField("customerName", this.customerName);
			addField("customerMobile", this.customerMobile);
			addField("nationality", this.nationality);
			addField("idNumber", this.idNumber);
			addField("pickupPoint", this.pickupPoint);
			addField("departureSeat", this.departureSeat);
			
			if(returnRoute != null) {
				addField("returnSeat", this.returnSeat);
				getAvailableSeats(this.returnSeat, availableReturnSeats);
			} else {
				this.returnSeat.setRequired(false);
			}
			
			if(isChild) {
				addField("childAge", this.childAge);
				this.childAge.setRequired(true);
				this.childAge.setRequiredError(Constants.ME_FIELDS_REQUIRED);
			}
		}
	}
	
	/**
	 * Gets a button used to go to the next step in the create booking form.
	 * 
	 * @return Button
	 */
	private Button getContinueButton(final Layout layout) {
		Button button = new Button("Continue");
		button.addStyleName("greenButton");
		button.setDisableOnClick(true);
		button.addListener(new Button.ClickListener() {
		    @Override
		    public void buttonClick(ClickEvent event) {
		    	BusApplication app = AppData.getApp();
	    		
				app.getMainLayout().getCenter().removeAllComponents();
				app.getMainLayout().getCenter().addComponent(layout);
				event.getButton().setEnabled(true);
		    }
		});
		
		return button;
	}
	
	/**
	 * Gets a button used to go to the previous step in the create booking form.
	 * 
	 * @return Button
	 */
	private Button getBackButton(final Layout layout) {
		Button button = new Button("Back");
		button.addStyleName("grayButton");
		button.setDisableOnClick(true);
		button.addListener(new Button.ClickListener() {
		    @Override
		    public void buttonClick(ClickEvent event) {
		    	BusApplication app = AppData.getApp();
	    		
				app.getMainLayout().getCenter().removeAllComponents();
				app.getMainLayout().getCenter().addComponent(layout);
				event.getButton().setEnabled(true);
		    }
		});
		
		return button;
	}

	/**
	 * Gets an radio option group to select a route.
	 * 
	 * @param fromSubstation
	 * @param toSubstation
	 * @param selectedDate
	 * @param isDeparture
	 * 
	 * @return OptionGroup
	 */
	public OptionGroup getRouteOptions(Integer fromSubstation, Integer toSubstation, Date selectedDate, Boolean isDeparture) {
		final OptionGroup optionGroup = new OptionGroup("Routes");
		optionGroup.setImmediate(true);
		
		BusApplication app = AppData.getApp();
		ServiceParameter sp = new ServiceParameter(new HashMap<String, String>());
		sp.param.put("fromSubstation", fromSubstation.toString());
		sp.param.put("toSubstation", toSubstation.toString());
		sp.param.put("startDate", Util.formatDateForDB(Util.getStartOfADay(selectedDate)));
		sp.param.put("endDate", Util.formatDateForDB(Util.getEndOfADay(selectedDate)));
		sp.param.put("isDeparture", isDeparture.toString());
		
		BeanContainer<Integer, Route> container = new BeanContainer<Integer, Route>(Route.class);
		container.setBeanIdProperty("routeId");
		
		DbServicesPrx dbServicesPrx = app.getDbServiceProxy();
		ServiceResult sr = dbServicesPrx.getRoutesBySubstationsAndDates(sp);
		if(sr.status) {
			if(sr.param.get("RECORDS") != null) {
				Results r = Util.getObjectsFromXmlResult(sr.param.get("RECORDS"), Route.class);
				for (Object object : r.getRows()) {
					Route route = (Route) object;
					container.addItem(route.getRouteId(), route);
				}
				optionGroup.setContainerDataSource(container);
			} else {
				optionGroup.setContainerDataSource(null);
			}
		} else {
			app.showErrorNotification(sr.message);
			optionGroup.setContainerDataSource(null);
		}
		optionGroup.setItemCaptionPropertyId("routeName");
		
		optionGroup.addListener(new ValueChangeListener() {
			@Override
			public void valueChange(ValueChangeEvent event) {
				
			}
		});
		return optionGroup;
	}
	
	/**
	 * Gets a button to save the form data.
	 * 
	 * @return Button
	 */
	private Button getSaveButton(final Form form, final Button print) {
		Button button = new Button("Save");
		button.addStyleName("blueButton");
		button.setDisableOnClick(true);
		button.addListener(new Button.ClickListener() {
		    @Override
		    public void buttonClick(ClickEvent event) {
		    	BusApplication app = (BusApplication) getApplication();
		    	if(form.isValid()) {
		    		Route route = ((BeanItem<Route>)((ComboBox)form.getField("route")).getContainerDataSource().getItem(form.getField("route").getValue())).getBean();
		    		BusFare busFare = ((BeanItem<BusFare>)((ComboBox)form.getField("amount")).getContainerDataSource().getItem(form.getField("amount").getValue())).getBean();
		    		
		    		List<String> departureTime = Arrays.asList(route.getDepartureTime().split(":"));
		    		List<String> reportingTime = Arrays.asList(route.getReportingTime().split(":"));
		    		
		    		Date travelDate = Util.setDateHourAndMinute((Date) form.getField("travelDate").getValue(), Integer.parseInt(departureTime.get(0)), Integer.parseInt(departureTime.get(1)), "pm".equalsIgnoreCase(route.getAmpm()));
		    		Date reportingDate = Util.setDateHourAndMinute((Date) form.getField("travelDate").getValue(), Integer.parseInt(reportingTime.get(0)), Integer.parseInt(reportingTime.get(1)), "pm".equalsIgnoreCase(route.getAmpm()));
		    		
		    		ServiceParameter sp = new ServiceParameter(new HashMap<String, String>());
		    		sp.param.put("userId", AppData.getUser().getUserId().toString());
		    		sp.param.put("travelDate", Util.formatDateForDB(travelDate));
		    		sp.param.put("reportingDate", Util.formatDateForDB(reportingDate));
		    		sp.param.put("loadingsheetId", route.getLoadingsheetId().toString());
		    		sp.param.put("seatId", form.getField("seat").getValue().toString());
		    		sp.param.put("name", form.getField("name").getValue().toString());
		    		sp.param.put("mobile", form.getField("mobile").getValue().toString());
		    		sp.param.put("nationality", form.getField("nationality").getValue().toString());
		    		sp.param.put("idNumber", form.getField("idNumber").getValue().toString());
		    		sp.param.put("childAge", form.getField("childAge").getValue().toString());
		    		sp.param.put("fromSubstation", form.getField("fromSubstation").getValue().toString());
		    		sp.param.put("toSubstation", form.getField("toSubstation").getValue().toString());
		    		sp.param.put("amount", busFare.getAmount().toString());
		    		sp.param.put("currencyName", busFare.getCurrencyName());
		    		sp.param.put("pickupPoint", form.getField("pickupPoint").getValue().toString());
		    		sp.param.put("bookingAction", ""+Constants.BOOKING_ACTION_BOOK);
		    		sp.param.put("bookingStatus", ""+Constants.BOOKING_STATUS_ACTIVE);
		    		sp.param.put("seatStatus", ""+Constants.SEAT_STATUS_UNAVAILABLE);
		    		
		    		Temp type = ((BeanItem<Temp>) bookingType.getContainerDataSource().getItem(bookingType.getValue())).getBean();
		    		sp.param.put("isOneWay", type.getId() == Constants.BOOKING_TYPE_ONE_WAY ? "1" : "0");
		    		
		    		DbServicesPrx dbServicesPrx = app.getDbServiceProxy();
		    		ServiceResult sr = dbServicesPrx.saveBooking(sp);
		    		
		    		if(sr.status) {
		    			form.setReadOnly(true);
		    			app.showNotification(Constants.MN_SUCCESSFULLY_SAVED);
		    			bookingId = sr.param.get("bookingId");
		    			actionDate = Util.formatDate(sr.param.get("actionDate"));
		    			print.setEnabled(true);
		    		} else {
		    			app.showErrorNotification(sr.message);
		    			event.getButton().setEnabled(true);
		    		}
		    	} else {
		    		app.showErrorNotification(Constants.ME_FORM_FIELDS_REQUIRED);
		    		event.getButton().setEnabled(true);
		    	}
		    }
		});
		
		return button;
	}
	
	/**
	 * Gets a button to save the form data.
	 * 
	 * @return Button
	 */
	public Button getPrintButton(final Form form) {
		Button button = new Button("Print");
		button.addStyleName("greenButton");
		button.setEnabled(false);
		button.setDisableOnClick(true);
		button.addListener(new Button.ClickListener() {
		    @Override
		    public void buttonClick(ClickEvent event) {
		    	if(form.isValid()) {
			        Window printWindow = getPrintWindow(event.getButton());
			        
			        Substation from = ((BeanItem<Substation>)((ComboBox)form.getField("fromSubstation")).getContainerDataSource().getItem(form.getField("fromSubstation").getValue())).getBean();
			        Substation to = ((BeanItem<Substation>)((ComboBox)form.getField("toSubstation")).getContainerDataSource().getItem(form.getField("toSubstation").getValue())).getBean();
		    		BusFare busFare = ((BeanItem<BusFare>)((ComboBox)form.getField("amount")).getContainerDataSource().getItem(form.getField("amount").getValue())).getBean();
		    		Route route = ((BeanItem<Route>)((ComboBox)form.getField("route")).getContainerDataSource().getItem(form.getField("route").getValue())).getBean();
		    		Seat seat = ((BeanItem<Seat>)((ComboBox)form.getField("seat")).getContainerDataSource().getItem(form.getField("seat").getValue())).getBean();
			        
			        CustomLayout printBookingLayout = new CustomLayout("printBooking");
			        printBookingLayout.addComponent(new Label(bookingId), "ticketNo");
			        printBookingLayout.addComponent(new Label(form.getField("name").getValue().toString()), "name");
			        printBookingLayout.addComponent(new Label(from.getName()), "from");
			        if(form.getField("pickupPoint").getValue() != null && !"".equalsIgnoreCase(form.getField("pickupPoint").getValue().toString()))
			        	printBookingLayout.addComponent(new Label("(Pickup: "+ form.getField("pickupPoint").getValue().toString() +")"), "pickupPoint");
			        printBookingLayout.addComponent(new Label(to.getName()), "to");
			        printBookingLayout.addComponent(new Label(seat.getDescription()), "seat");
			        printBookingLayout.addComponent(new Label(form.getField("idNumber").getValue().toString()), "idNo");
			        printBookingLayout.addComponent(new Label(form.getField("mobile").getValue().toString()), "mobileNo");
			        printBookingLayout.addComponent(new Label("Fair paid ("+ busFare.getCurrencyName() +"):"), "currencyName");
			        printBookingLayout.addComponent(new Label("Child age: "+ form.getField("childAge").getValue().toString()), "childAge");
			        printBookingLayout.addComponent(new Label(actionDate), "issueDate");
			        printBookingLayout.addComponent(new Label(Util.formatDateWithoutTime((Date) form.getField("travelDate").getValue())), "travelDate");
			        printBookingLayout.addComponent(new Label(Util.formatMoney(busFare.getAmount().toString())), "amount");
			        printBookingLayout.addComponent(new Label(route.getReportingTime() +" "+ route.getAmpm()), "reportingTime");
			        printBookingLayout.addComponent(new Label(route.getDepartureTime() +" "+ route.getAmpm()), "departureTime");
			        printBookingLayout.addComponent(new Label(AppData.getUser().toString()), "userFullName");
			        
			        // Have some content to print
			        printWindow.addComponent(printBookingLayout);

		    		event.getButton().setEnabled(true);
		    	}
		    }
		});
		
		return button;
	}
	
	/**
	 * Gets a window that is used to print a booking.
	 * 
	 * @param button
	 * 
	 * @return Window
	 */
	private Window getPrintWindow(Button button) {
		// Create a window that contains what you want to print
        Window printWindow = new Window();
        printWindow.setCaption("");
        
        // Add the printing window as a new application-level window
        button.getApplication().addWindow(printWindow);

        // Open it as a popup window with no decorations
        button.getWindow().open(new ExternalResource(printWindow.getURL()));
        //getWindow().open(new ExternalResource(printWindow.getURL()), "_blank");

        // Print automatically when the window opens. This call will block until the print dialog exits!
        //printWindow.executeJavaScript("print();");

        // Close the window automatically after printing
        //printWindow.executeJavaScript("self.close();");
        return printWindow;
	}
}